package com.example.onlinetaxi.util.OKHttpUtil;

import android.util.Log;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 * 异步请求会放到线程池中执行
 * 同步请求会阻塞当前线程
 * 一般使用异步请求居多
 */
public class OKHttpUtil {

    private static Request request = null;
    private static int TimeOut = 120;
    //单例获取okhttp3客户端对象
    private static OkHttpClient client = null;

    /**
     * OkHttpClient的构造方法，通过线程锁synchronized的方式构造
     *
     * @return OkHttpClient对象
     */
    private static synchronized OkHttpClient getInstance() {
        if (client == null) {
            client = new OkHttpClient.Builder()
                    .readTimeout(TimeOut, TimeUnit.SECONDS)
                    .connectTimeout(TimeOut, TimeUnit.SECONDS)
                    .writeTimeout(TimeOut, TimeUnit.SECONDS)
                    .build();
        }
        return client;
    }

    /**
     * callback接口，适配器模式
     * 异步请求时使用
     */
    static class MyCallBack implements Callback {
        private OKHttpCallback okHttpCallBack;

        public MyCallBack(OKHttpCallback okHttpCallBack) {
            this.okHttpCallBack = okHttpCallBack;
        }

        @Override
        public void onFailure(Call call, IOException e) {
            okHttpCallBack.onFailure(e);
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            okHttpCallBack.onSuccess(response);
        }
    }

    /**
     * 获得同步get请求对象Response
     *
     * @param url
     * @return Response
     */
    private static Response doSyncGet(String url) {
        // 获取client实例
        client = getInstance();
        // 创建请求
        request = new Request.Builder()
                .url(url)//请求链接
                .build();//创建Request对象

        // 发送请求并返回Response对象
        try {
            Response response = client.newCall(request).execute();
            return response;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获得异步get请求对象
     *
     * @param url      请求地址
     * @param callback 实现callback接口
     */
    private static void doAsyncGet(String url, OKHttpCallback callback) {
        // 定义反馈实例
        MyCallBack myCallback = new MyCallBack(callback);
        // 获取客户端实例
        client = getInstance();
        // 发送请求
        request = new Request.Builder()
                .url(url)
                .get()
                .build();
        // 发送请求并加入反馈队列
        client.newCall(request).enqueue(myCallback);
    }

    /**
     * 同步get请求
     * 例如：请求的最终地址为：http://127.0.0.1:8081/user/getUser/123
     *
     * @param url  基本请求地址   例子： http://127.0.0.1:8081
     * @param args 请求的参数    args[]=new String[]{"user","getUser","123"}
     * @return String
     */
    public static String getSyncRequest(String url, String... args) {
        // 接收返回值
        List<String> result = new ArrayList<>();

        // 基本地址
        String address = url;
        // 实现地址拼接
        for (int i = 0; i < args.length; i++) {
            address = address + "/" + args[i];
        }
        // 最终地址
        final String finalAddress = address;

        // 创建线程，发送同步get请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 发送同步get请求，获得返回数据
                Response finalResponse = doSyncGet(finalAddress);
                String res = null;
                try {
                    // 打印请求信息
                    Log.d("同步get请求请求地址：", finalAddress);
                    // 请求成功
                    if (finalResponse.isSuccessful()) {
                        // 拿到响应体
                        ResponseBody body = finalResponse.body();
                        res = body.string();
                        // 加入result中
                        result.add(res);
                        // 打印成功信息
                        Log.d("HttpUtil", "同步get请求成功！");
                        Log.d("请求对象：", res);
                    } else {
                        // 请求失败
                        Log.d("HttpUtil", "同步get请求失败！");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        // 因为函数返回是立刻执行的，而result要在请求完成之后才能获得
        // 所以需要等待result获得返回值之后再执行return
        while (result.size() == 0) {
            try {
                TimeUnit.MILLISECONDS.sleep(10);//等待xx毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 返回请求信息
        return result.get(0);
    }


    /**
     * 异步get请求
     * 例如：请求的最终地址为：http://127.0.0.1:8081/user/getUser/123
     *
     * @param url  基本请求地址   例子： http://127.0.0.1:8081
     * @param args 请求的参数    args[]=new String[]{"user","getUser","123"}
     * @return String
     */
    public static String getAsyncRequest(String url, String... args) {
        // 接收返回值
        List<String> result = new ArrayList<>();

        // 基本地址
        String address = url;
        // 实现地址拼接
        for (int i = 0; i < args.length; i++) {
            address = address + "/" + args[i];
        }
        // 最终地址
        final String finalAddress = address;

        // 发送异步请求，并设置回调函数
        doAsyncGet(finalAddress, new OKHttpCallback() {
            @Override
            public void onFailure(IOException e) {
                // 请求失败
                Log.d("异步get请求地址：", finalAddress);
                Log.d("HttpUtil", "异步get请求失败！");
            }

            @Override
            public void onSuccess(Response response) {
                // 请求成功
                Log.d("异步get请求地址：", finalAddress);
                String res = null;
                try {
                    res = response.body().string();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                // 打印成功信息
                result.add(res);
                Log.d("HttpUtil", "异步get请求成功！");
                Log.d("请求对象：", res);
            }
        });

        // 因为函数返回是立刻执行的，而result要在请求完成之后才能获得
        // 所以需要等待result获得返回值之后再执行return
        while (result.size() == 0) {
            try {
                TimeUnit.MILLISECONDS.sleep(10);//等待xx毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 返回请求到的数据
        return result.get(0);
    }

    /**
     * 同步post请求
     * 例如：请求的最终地址为：http://127.0.0.1:8081/user/getUser/123
     *
     * @param url  基本请求地址   例子： http://127.0.0.1:8081
     * @param map  提交的请求对象
     * @param args 请求的参数    args[]=new String[]{"user","getUser","123"}
     * @return String
     */
    public static String postSyncRequest(String url, Map map, String... args) {
        // 接收返回值
        List<String> result = new ArrayList<>();

        // 基本地址
        String address = url;
        // 实现地址拼接
        for (int i = 0; i < args.length; i++) {
            address = address + "/" + args[i];
        }
        // 最终地址
        final String finalAddress = address;

        // 创建线程发起同步传递
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 获取实例
                client = getInstance();
                Log.d("同步post请求地址：", finalAddress);
                // 创建请求体
                RequestBody requestBody = RequestUtil.getRequestBody(map);
                // 创建请求
                request = new Request.Builder()
                        .url(finalAddress)  // 请求url
                        .post(requestBody)  // 发送请求体
                        .addHeader("device-platform", "android")  // 请求头
                        .build();
                try {
                    // 发起异步post请求
                    Response response = client.newCall(request).execute();
                    String res = response.body().string();
                    result.add(res);
                    // 请求发送成功
                    Log.d("HttpUtil", "同步post请求成功！");
                    Log.d("请求对象：", res);
                } catch (Exception e) {
                    Log.d("HttpUtil", "同步post请求失败！");
                    e.printStackTrace();
                }
            }
        }).start();

        // 因为函数返回是立刻执行的，而result要在请求完成之后才能获得
        // 所以需要等待result获得返回值之后再执行return
        while (result.size() == 0) {
            try {
                TimeUnit.MILLISECONDS.sleep(10);//等待xx毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 返回接收到的数据
        return result.get(0);
    }

    /**
     * 异步post请求
     * 例如：请求的最终地址为：http://127.0.0.1:8081/user/getUser/123
     *
     * @param url  基本请求地址   例子： http://127.0.0.1:8081
     * @param map 提交的map表单
     * @param args 请求的参数    args[]=new String[]{"user","getUser","123"}
     * @return
     */
    // 异步调用传参：url,map,args
    public static String postAsyncRequest(String url, Map map, String... args) {
        // 接收返回值
        List<String> result = new ArrayList<>();

        // 基本地址
        String address = url;
        // 实现地址拼接
        for (int i = 0; i < args.length; i++) {
            address = address + "/" + args[i];
        }
        // 最终地址
        final String finalAddress = address;
        Log.d("异步post请求地址：", finalAddress);

        // 获取客户端实例
        client = getInstance();
        // 创建请求体
        RequestBody requestBody = RequestUtil.getRequestBody(map);
        request = new Request.Builder()
                .url(finalAddress)
                .post(requestBody)
                .addHeader("device-platform", "android")
                .build();

        // 发送请求，调用回调方法
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                // 请求失败
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Log.d("HttpUtil", "异步post请求失败！");
                    }
                }).start();
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        String res = null;
                        try {
                            res = response.body().string();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        result.add(res);
                        // 请求成功
                        Log.d("HttpUtil", "异步post请求成功！");
                        Log.d("请求对象", res);
                    }
                }).start();
            }
        });

        // 因为函数返回是立刻执行的，而result要在请求完成之后才能获得
        // 所以需要等待result获得返回值之后再执行return
        while (result.size() == 0) {
            try {
                TimeUnit.MILLISECONDS.sleep(10);//等待xx毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 返回获取的请求
        return result.get(0);
    }
}